#pragma once

#include <fstream>

#include "../../test.h"
#include "../Number.hpp"

namespace header
{
namespace test
{

TEST(NumberPrivateFunc)
{
    Number n;
    std::string num = "-000.0000";
    n.delete_pre_0(num);
    EXPECT_EQ("-0.0000", num);
    n.delete_suf_0(num);
    EXPECT_EQ("0", num);

    num = "000.";
    n.delete_pre_0(num);
    EXPECT_EQ("0.", num);

    num = "1.0";
    n.delete_pre_0(num);
    EXPECT_EQ("1.0", num);
    n.delete_suf_0(num);
    EXPECT_EQ("1", num);

    num = "0.1000";
    n.delete_pre_0(num);
    EXPECT_EQ("0.1000", num);
    n.delete_suf_0(num);
    EXPECT_EQ("0.1", num);

    num = "-100.0000";
    n.delete_suf_0(num);
    EXPECT_EQ("-100", num);
    n.delete_suf_0(num);
    EXPECT_EQ("-100", num);

    num = "-000.001";
    n.delete_pre_0(num);
    EXPECT_EQ("-0.001", num);
}

TEST(NumberPrivateIntFunc)
{
    Number n;
    // ==================== cmp =======================
    EXPECT_EQ(0, n.cmp_int("0", "0"));
    EXPECT_EQ(-1, n.cmp_int("3", "10"));
    EXPECT_EQ(1, n.cmp_int("100", "99"));
    EXPECT_EQ(1, n.cmp_int("123", "111"));

    // ==================== add =======================
    EXPECT_EQ("100998", n.add_int("99999", "00999"));
    EXPECT_EQ("100", n.add_int("99", "1"));
    EXPECT_EQ("987654321", n.add_int("987654321", "0"));
    EXPECT_EQ("1975308643975308642", n.add_int("987654321987654321", "987654321987654321"));
    EXPECT_EQ("0", n.add_int("0", "0"));
    EXPECT_EQ("2222222", n.add_int("1111111", "1111111"));

    // ==================== sub =======================
    EXPECT_EQ("-1", n.sub_int("6", "7"));
    EXPECT_EQ("6", n.sub_int("10", "4"));
    EXPECT_EQ("1", n.sub_int("200", "199"));
    EXPECT_EQ("3", n.sub_int("100", "97"));
    EXPECT_EQ("-3", n.sub_int("97", "100"));
    EXPECT_EQ("99000", n.sub_int("99999", "999"));
    EXPECT_EQ("-99000", n.sub_int("999", "99999"));
    EXPECT_EQ("987654321", n.sub_int("987654321", "0"));
    EXPECT_EQ("-987654321", n.sub_int("0", "987654321"));
    EXPECT_EQ("987654321864197532", n.sub_int("987654321987654321", "123456789"));
    EXPECT_EQ("-999999998888888888888888", n.sub_int("1111111111111111", "999999999999999999999999"));
    EXPECT_EQ("0", n.sub_int("0", "0"));

    // ==================== mul =======================
    EXPECT_EQ("0", n.mul_int("99999", "0"));
    EXPECT_EQ("0", n.mul_int("0", "999"));
    EXPECT_EQ("99899001", n.mul_int("99999", "999"));
    EXPECT_EQ("99899001", n.mul_int("999", "99999"));
    EXPECT_EQ("12193254061881", n.mul_int("1234567", "9876543"));
    EXPECT_EQ("8888888879111111112", n.mul_int("9999999999", "888888888"));

    // ==================== div =======================
    EXPECT_EQ("141093474.428571", n.div_int("987654321", "7"));     // 3 / 7
    EXPECT_EQ("5", n.div_int("10", "2"));
    EXPECT_EQ("12.666667", n.div_int("38", "3"));
    EXPECT_EQ("0.4286", n.div_int("3", "7", 4));
    EXPECT_EQ("0.42", n.div_int("3", "7", 2, Number::DivFlag::truncate));
    EXPECT_EQ("0", n.div_int("0", "10"));
    EXPECT_EQ("0.030303030303030", n.div_int("1", "33", 15));
    EXPECT_EQ("0.333333", n.div_int("1", "3"));
    TRY(n.div_int("99999", "0"), NumberExcep);
    EXPECT_EQ("0.0007", n.div_int("7", "9876", 4));
    EXPECT_EQ("3", n.div_int("10", "3", 0));
    EXPECT_EQ("3846.003115", n.div_int("1234567", "321"));
}

TEST(NumberPrivateDoubleFunc)
{    
    Number n;
    // =================== cmp ========================
    EXPECT_EQ(1, n.cmp_double("123", 2, "122", 2));
    EXPECT_EQ(1, n.cmp_double("9", 2, "8", 2));
    EXPECT_EQ(1, n.cmp_double("9", 1, "8", 2));
    EXPECT_EQ(0, n.cmp_double("123", 2, "123", 2));
    EXPECT_EQ(0, n.cmp_double("0", 2, "0", 1));
    EXPECT_EQ(0, n.cmp_double("0", 2, "0", 2));
    EXPECT_EQ(-1, n.cmp_double("123", 2, "124", 2));
    EXPECT_EQ(-1, n.cmp_double("9", 2, "1", 1));
    EXPECT_EQ(-1, n.cmp_double("0", 0, "1", 2));
    
    // ==================== del =======================
    std::string num = "-000.0000";
    n.delete_pre_0(num);
    EXPECT_EQ("-0.0000", num);
    n.delete_suf_0(num);
    EXPECT_EQ("0", num);

    num = "000.";
    n.delete_pre_0(num);
    EXPECT_EQ("0.", num);

    num = "1.0";
    n.delete_pre_0(num);
    EXPECT_EQ("1.0", num);
    n.delete_suf_0(num);
    EXPECT_EQ("1", num);

    num = "0.1000";
    n.delete_pre_0(num);
    EXPECT_EQ("0.1000", num);
    n.delete_suf_0(num);
    EXPECT_EQ("0.1", num);

    num = "-100.0000";
    n.delete_suf_0(num);
    EXPECT_EQ("-100", num);
    n.delete_suf_0(num);
    EXPECT_EQ("-100", num);

    num = "-000.001";
    n.delete_pre_0(num);
    EXPECT_EQ("-0.001", num);

    // ================= to_double ====================
    EXPECT_EQ("0", n.to_double("0", 2));
    EXPECT_EQ("-0.001", n.to_double("-1", 3));
    EXPECT_EQ("+1.00", n.to_double("+100", 2));
    EXPECT_EQ("0.10", n.to_double("10", 2));
    EXPECT_EQ("-1.23", n.to_double("-123", 2));
    
    // ==================== add =======================
    EXPECT_EQ("0", n.add_double("0", 1, "0", 2));
    EXPECT_EQ("0.100", n.add_double("99", 3, "1", 3));
    EXPECT_EQ("100.0989", n.add_double("99999", 3, "999", 4));
    EXPECT_EQ("0.987654321", n.add_double("987654321", 9, "0", 0));
    EXPECT_EQ("9877530874198.530864321", n.add_double("987654321987654321", 9, "987654321987654321", 5));
    EXPECT_EQ("2222222", n.add_double("1111111", 0, "1111111", 0));

    // ==================== sub =======================
    EXPECT_EQ("-0.03", n.sub_double("97", 2, "100", 2));
    EXPECT_EQ("0.01", n.sub_double("200", 2, "199", 2));
    EXPECT_EQ("99.03", n.sub_double("100", 0, "97", 2));
    EXPECT_EQ("-6.4", n.sub_double("6", 1, "7", 0));
    EXPECT_EQ("-3.0", n.sub_double("10", 1, "4", 0));
    EXPECT_EQ("0.099", n.sub_double("99999", 3, "999", 1));
    EXPECT_EQ("-0.0099", n.sub_double("999", 2, "99999", 4));
    EXPECT_EQ("9.87654321", n.sub_double("987654321", 8, "0", 0));
    EXPECT_EQ("-0.987654321", n.sub_double("0", 0, "987654321", 9));
    EXPECT_EQ("9876543218.64197532", n.sub_double("987654321987654321", 8, "123456789", 8));
    EXPECT_EQ("-99999999.8888888888888888", n.sub_double("1111111111111111", 16, "999999999999999999999999", 16));
    EXPECT_EQ("0", n.sub_double("0", 0, "0", 0));

    // ==================== mul =======================
    EXPECT_EQ("0", n.mul_double("99999", 3, "0", 0));
    EXPECT_EQ("0", n.mul_double("0",0, "999", 1));
    EXPECT_EQ("998.99001", n.mul_double("99999", 3, "999", 2));
    EXPECT_EQ("99.899001", n.mul_double("999", 3, "99999", 3));
    EXPECT_EQ("12193254.061881", n.mul_double("1234567", 3, "9876543", 3));
    EXPECT_EQ("888888887911111.1112", n.mul_double("9999999999", 2, "888888888", 2));

    // ==================== div =======================
    EXPECT_EQ("0.990000", n.div_double("297", 2, "3", 0));
    EXPECT_EQ("1.0", n.div_double("297", 2, "3", 0, 1));
    EXPECT_EQ("1", n.div_double("297", 2, "3", 0, 0));
    EXPECT_EQ("0", n.div_double("297", 2, "3", 0, 0, Number::DivFlag::truncate));
    TRY(n.div_double("99999", 3, "0", 0), NumberExcep);
    EXPECT_EQ("0.50", n.div_double("10", 1, "2", 0, 2));
    EXPECT_EQ("0", n.div_double("0", 1, "10", 2));
    EXPECT_EQ("0.033", n.div_double("1", 1, "3", 0, 3));
    EXPECT_EQ("0.00303030303030", n.div_double("1", 3, "33", 2, 14));
    EXPECT_EQ("1410.935", n.div_double("987654321", 5, "7", 0, 3));
    EXPECT_EQ("0.7088", n.div_double("7", 0, "9876", 3, 4));
    EXPECT_EQ("0.333333", n.div_double("10", 1, "3", 0));
    EXPECT_EQ("3.84600", n.div_double("1234567", 4, "321", 1, 5));
    EXPECT_EQ("0.00033", n.div_double("1", 3, "3", 0, 5));

    // ==================== mod =======================
    TRY(n.mod("3", 0, "0", 0), NumberExcep);
    EXPECT_EQ("1.55", n.mod("12345", 2, "23", 1));
    EXPECT_EQ("1.0", n.mod("31", 1, "21", 1));
    EXPECT_EQ("1.25", n.mod("12345", 2, "26", 1));
    EXPECT_EQ("0", n.mod("0", 0, "1", 0));
    EXPECT_EQ("1", n.mod("3", 0, "2", 0));
    EXPECT_EQ("1.1", n.mod("31", 1, "2", 0));
    EXPECT_EQ("11", n.mod("31", 0, "20", 0));

    // ==================== cal_digit_point_signed =====================
    num = ".001";
    int p = 0;
    bool is_signed = false;
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("1", num);
    EXPECT_EQ(3, p);
    EXPECT_FALSE(is_signed);

    num = "+10.";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("10", num);
    EXPECT_EQ(0, p);
    EXPECT_FALSE(is_signed);

    num = "0.0123";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("123", num);
    EXPECT_EQ(4, p);
    EXPECT_FALSE(is_signed);
    
    num = "+10.00";
    n.cal_digit_point_signed(num, p, is_signed, true);
    EXPECT_EQ("1000", num);
    EXPECT_EQ(2, p);
    EXPECT_FALSE(is_signed);
    
    num = "-1.00";
    n.cal_digit_point_signed(num, p, is_signed, true);
    EXPECT_EQ("100", num);
    EXPECT_EQ(2, p);
    EXPECT_TRUE(is_signed);

    num = "-1.";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("1", num);
    EXPECT_EQ(0, p);
    EXPECT_TRUE(is_signed);

    num = "-0";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("0", num);
    EXPECT_EQ(0, p);
    EXPECT_FALSE(is_signed);
    
    num = "+0";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("0", num);
    EXPECT_EQ(0, p);
    EXPECT_FALSE(is_signed);
    
    num = "-.0";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("0", num);
    EXPECT_EQ(0, p);
    EXPECT_FALSE(is_signed);

    num = "+.01";
    n.cal_digit_point_signed(num, p, is_signed);
    EXPECT_EQ("1", num);
    EXPECT_EQ(2, p);
    EXPECT_FALSE(is_signed);

    // ================== legal number ======================
    EXPECT_TRUE(n.is_legal_number("0.0"));
    EXPECT_TRUE(n.is_legal_number("12"));
    EXPECT_TRUE(n.is_legal_number("+12.01"));
    EXPECT_TRUE(n.is_legal_number("-0.01"));
    EXPECT_TRUE(n.is_legal_number("0."));
    EXPECT_TRUE(n.is_legal_number(".0"));
    EXPECT_TRUE(n.is_legal_number("+3."));
    EXPECT_TRUE(n.is_legal_number("+.1"));
    EXPECT_TRUE(n.is_legal_number("-.2"));
    EXPECT_TRUE(n.is_legal_number("-4."));
    EXPECT_FALSE(n.is_legal_number("."));
    EXPECT_FALSE(n.is_legal_number("=7.8"));
}

TEST(Number)
{
    Number num1("2147483.648"), num2("+12345.6789");
    Number num3("+2147483.648"), num4("-12345.6789");
    Number num5("-2147483.648"), num6("12345.6789");
    Number num7("-2147483.648"), num8("-12345.6789");
    Number num9("-0"), num10("+0");
    Number num11("0"), num12("123.45678");
    Number num13("-0"), num14("-123.45678");

    // ===================== + ======================
    EXPECT_EQ(Number{"002159829.326900"}, num1 + num2);
    EXPECT_EQ(Number{"2135137.9691"}, num3 + num4);
    EXPECT_EQ(Number{"-002135137.9691"}, num5 + num6);
    EXPECT_EQ(Number{"-2159829.32690"}, num7 + num8);
    EXPECT_EQ(Number{"0"}, num9 + num10);
    EXPECT_EQ(Number{"0123.456780"}, num11 + num12);
    EXPECT_EQ(Number{"-123.45678"}, num13 + num14);
    
    // ==================== += ======================
    Number num{"2147483.648"};
    num += num2;
    EXPECT_EQ(Number{"2159829.3269"}, num);
    EXPECT_EQ(Number{"12345.6789"}, num2);

    // ===================== - ======================
    EXPECT_EQ("-2", (Number{"0"} - "2").str());
    EXPECT_EQ(Number{"2135137.9691"}, num1 - num2);
    EXPECT_EQ(Number{"2159829.3269"}, num3 - num4);
    EXPECT_EQ(Number{"-2159829.3269"}, num5 - num6);
    EXPECT_EQ(Number{"-2135137.9691"}, num7 - num8);
    EXPECT_EQ(Number{"00.000000"}, num9 - num10);
    EXPECT_EQ(Number{"-123.45678"}, num11 - num12);
    EXPECT_EQ(Number{"123.45678"}, num13 - num14);

    // ==================== -= ======================
    num = num1;
    EXPECT_EQ(Number{"2147483.648"}, num1);
    EXPECT_EQ(num1, num);    
    num -= num1;
    EXPECT_EQ(Number{"-000.0"}, num);
    num -= num1;
    EXPECT_EQ(Number{"-2147483.648"}, num);
    
    // ===================== * ======================
    EXPECT_EQ(Number{"26512143561.2086272"}, num1 * num2);
    EXPECT_EQ(Number{"-26512143561.2086272"}, num3 * num4);
    EXPECT_EQ(Number{"-26512143561.2086272"}, num5 * num6);
    EXPECT_EQ(Number{"26512143561.2086272"}, num7 * num8);
    EXPECT_EQ(Number{"0"}, num9 * num10);
    EXPECT_EQ(Number{"+0"}, num11 * num12);
    EXPECT_EQ(Number{"-0"}, num13 * num14);

    // ==================== *= ======================
    num = num1;
    num *= num2;
    EXPECT_EQ(num1 * num2, num);
    
    // ===================== / ======================
    EXPECT_EQ(Number{"0173"}, num1 / num2);
    EXPECT_EQ(Number{"-00173.94620"}, num3.div(num4, 4));
    EXPECT_EQ(Number{"-173"}, num5 / num6);
    EXPECT_EQ(Number{"173.946177"}, num7.div(num8));
    TRY(num9 / num10, NumberExcep);
    EXPECT_EQ(Number{"0"}, num11 / num12);
    EXPECT_EQ(Number{"0"}, num13.div(num14));

    // =================== /= =======================
    num = num1;
    num /= num2;
    EXPECT_EQ(num1 / num2, num);

    // ==================== % =======================
    TRY(Number{"1"} % "0", NumberExcep);
    EXPECT_EQ(Number{"1"}, Number{"03"} % "02");
    EXPECT_EQ(Number{"1"}, Number{"3"} % "-002");
    EXPECT_EQ(Number{"-1"}, Number{"-003"} % "2");
    EXPECT_EQ(Number{"-1"}, Number{"-3"} % "-2");
    EXPECT_EQ(Number{"11"}, Number{"31"} % "20");
    EXPECT_EQ(Number{"1"}, Number{"3.100"} % "2.10");
    EXPECT_EQ(Number{"1.1"}, Number{"3.1"} % "2");
    EXPECT_EQ(Number{"01.55"}, Number{"0123.45"} % "2.30");
    EXPECT_EQ(Number{"1.25"}, Number{"123.45"} % "2.6");
    
    // ==================== %= ======================
    num = "3";
    num %= "2";
    EXPECT_EQ(Number{"1"}, num);
    num = "-3";
    num %= "-2";
    EXPECT_EQ(Number{"-1"}, num);

    // ==================== ^ =======================
    TRY(Number{"1.1"} ^ "0.1", NumberExcep);
    EXPECT_EQ(Number{"0"}, Number{"0"} ^ "123456");
    EXPECT_EQ(Number{"1"}, Number{"123.456"} ^ "0.00");
    EXPECT_EQ(Number{"123456789"}, Number{"123456789"} ^ "1.00");
    EXPECT_EQ(Number("0.2500", true), Number{"2"} ^ "-2");
    EXPECT_EQ(Number{"4"}, Number{"2"} ^ "2.00");
    EXPECT_EQ(Number{"1267650600228229401496703205376"}, Number{"2"} ^ "100");
    EXPECT_EQ(Number{"81962.8286980801"}, Number{"3.1"} ^ "10");

    // ==================== ^= ======================
    num = "0";
    num ^= "0";
    EXPECT_EQ(Number{"1"}, num);
    num = "3.1";
    num ^= "10";
    EXPECT_EQ(Number{"81962.8286980801"}, num);

    // =================== == ====================
    EXPECT_TRUE(Number{"0"} == "0");
    EXPECT_TRUE(Number{"-0"} == "+0");
    EXPECT_TRUE(Number{"0"} == "-.0");
    EXPECT_TRUE(Number{"0."} == "0");
    EXPECT_TRUE(Number{"0.00"} == "0");
    EXPECT_TRUE(Number{"+0.0"} == "0");
    EXPECT_TRUE(Number{"-0"} == "0.00");
    EXPECT_TRUE(Number{"+123"} == "00123");
    EXPECT_TRUE(Number{"0000123"} == "+00123");
    EXPECT_TRUE(Number{"-12300"} == "-0012300");
    EXPECT_TRUE(Number{"+.12"} == "0.12");
    EXPECT_TRUE(Number{".120"} == "0000.12");
    EXPECT_TRUE(Number{"-.12"} == "-0.12");
    EXPECT_TRUE(Number{"1.23"} == "1.23");
    EXPECT_TRUE(Number{"1.2300"} == "001.23");
    EXPECT_TRUE(Number{"1.23"} == "01.23000");
    EXPECT_TRUE(Number{"+1.23"} == "+1.23");
    EXPECT_TRUE(Number{"+01.2300"} == "+1.23");
    EXPECT_TRUE(Number{"-1.23"} == "-1.23");
    EXPECT_TRUE(Number{"-001.230"} == "-1.23000");

    // =================== > ======================
    EXPECT_TRUE(Number{"123"} > "122");
    EXPECT_TRUE(Number{"00123"} > "122");
    EXPECT_TRUE(Number{"123"} > "00122");
    EXPECT_TRUE(Number{"10"} > "009.");
    EXPECT_TRUE(Number{"10."} > "9");
    EXPECT_TRUE(Number{"1.230001"} > "1.23");
    EXPECT_TRUE(Number{"001.230001"} > "1.230000");
    EXPECT_TRUE(Number{"1.230001"} > "1.23000001");
    EXPECT_TRUE(Number{"1.230001"} > "-1.23001");
    EXPECT_TRUE(Number{"001.230001000"} > "-1.23001");
    EXPECT_TRUE(Number{"-1.230001"} > "-1.23001");
    EXPECT_TRUE(Number{"-001.230001"} > "-1.23001000");
    
    // =================== >= ======================
    EXPECT_TRUE(Number{"-1.230001"} >= "-1.23001");
    EXPECT_TRUE(Number{"-1.230001"} >= "-1.230001");

    // =================== < ======================
    EXPECT_TRUE(Number{"1"} < "2");
    EXPECT_TRUE(Number{"001"} < "2.");
    EXPECT_TRUE(Number{"1."} < "1.2");
    EXPECT_TRUE(Number{"1."} < "+1.001");
    EXPECT_TRUE(Number{"-1."} < "+1");
    EXPECT_TRUE(Number{"1.230001"} < "+1.23001");
    EXPECT_TRUE(Number{"+1.23000100"} < "01.23001");
    EXPECT_TRUE(Number{"-1.230001"} < "1.23001");
    EXPECT_TRUE(Number{"-1.230001"} < "0001.23001000");
    EXPECT_TRUE(Number{"-1.2301"} < "-1.23001");
    EXPECT_TRUE(Number{"-001.2301"} < "-1.230010");
    
    // =================== <= ======================
    EXPECT_TRUE(Number{"1"} <= "2");
    EXPECT_TRUE(Number{"1.0"} <= "1.");
    EXPECT_TRUE(Number{"-1.230001"} <= "0001.23001000");
    EXPECT_TRUE(Number{"-1.2301"} <= "-1.23001");
    
    // ==================== >> ======================
    std::ifstream ifs("1.in");
    std::ofstream ofs("1.out");
    while (true) {
        if (ifs.eof()) break;
        ifs >> num;
        if (ifs.fail()) {
            ifs.clear();
            ifs.get();
            continue;
        }
        ofs << num << std::endl;
    }
}

}   // namespace test
}   // namespace header
